<p>This vulnerability allows attackers to impersonate a trusted host.</p>
<h2>Why is this an issue?</h2>
<p>Transport Layer Security (TLS) provides secure communication between systems over the internet by encrypting the data sent between them. In this
process, the role of hostname validation, combined with certificate validation, is to ensure that a system is indeed the one it claims to be, adding
an extra layer of trust and security.</p>
<p>When hostname validation is disabled, the client skips this critical check. This creates an opportunity for attackers to pose as a trusted entity
and intercept, manipulate, or steal the data being transmitted.</p>
<p>To do so, an attacker would obtain a valid certificate authenticating <code>example.com</code>, serve it using a different hostname, and the
application code would still accept it.</p>
<h3>What is the potential impact?</h3>
<p>Establishing trust in a secure way is a non-trivial task. When you disable hostname validation, you are removing a key mechanism designed to build
this trust in internet communication, opening your system up to a number of potential threats.</p>
<h4>Identity spoofing</h4>
<p>If a system does not validate hostnames, it cannot confirm the identity of the other party involved in the communication. An attacker can exploit
this by creating a fake server and masquerading it as a legitimate one. For example, they might set up a server that looks like your bank’s server,
tricking your system into thinking it is communicating with the bank. This scenario, called identity spoofing, allows the attacker to collect any data
your system sends to them, potentially leading to significant data breaches.</p>
<h2>How to fix it in Apache Commons Email</h2>
<h3>Code examples</h3>
<p>The following code contains examples of disabled hostname validation.</p>
<p>The hostname validation gets disabled because <code>setSSLCheckServerIdentity</code> is omitted. To enable validation, set it to
<code>true</code>.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="1" data-diff-type="noncompliant">
import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.SimpleEmail;

public void sendMail(String message) {
    Email email = new SimpleEmail();

    email.setMsg(message);
    email.setSmtpPort(465);
    email.setAuthenticator(new DefaultAuthenticator(username, password));
    email.setSSLOnConnect(true); // Noncompliant

    email.send();
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="1" data-diff-type="compliant">
import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.SimpleEmail;

public void sendMail(String message) {
    Email email = new SimpleEmail();

    email.setMsg(message);
    email.setSmtpPort(465);
    email.setAuthenticator(new DefaultAuthenticator(username, password));
    email.setSSLCheckServerIdentity(true);
    email.setSSLOnConnect(true);

    email.send();
}
</pre>
<h3>How does this work?</h3>
<p>To fix the vulnerability of disabled hostname validation, it is strongly recommended to first re-enable the default validation and fix the root
cause: the validity of the certificate.</p>
<h4>Use valid certificates</h4>
<p>If a hostname validation failure prevents connecting to the target server, keep in mind that <strong>one system’s code should not work around
another system’s problems</strong>, as this creates unnecessary dependencies and can lead to reliability issues.</p>
<p>Therefore, the first solution is to change the remote host’s certificate to match its identity. If the remote host is not under your control,
consider replicating its service to a server whose certificate you can change yourself.</p>
<p>In case the contacted host is located on a development machine, and if there is no other choice, try following this solution:</p>
<ul>
  <li> Create a self-signed certificate for that machine. </li>
  <li> Add this self-signed certificate to the system’s trust store. </li>
  <li> If the hostname is not <code>localhost</code>, add the hostname in the <code>/etc/hosts</code> file. </li>
</ul>
<p>Here is a sample command to import a certificate to the Java trust store:</p>
<pre>
keytool -import -alias myserver -file myserver.crt -keystore cacerts
</pre>
<h2>How to fix it in Java SE</h2>
<h3>Code examples</h3>
<p>The following code contains examples of disabled hostname validation.</p>
<p>The hostname validation gets disabled by overriding <code>javax.net.ssl.HostnameVerifier.verify()</code> with an empty implementation. It is highly
recommended to use the original implementation.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="21" data-diff-type="noncompliant">
import java.io.InputStream;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.HostnameVerifier;

public InputStream doRequest() {
    URL url                          = new URL("https://example.org/");
    HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();

    urlConnection.setHostnameVerifier(new HostnameVerifier() {
      @Override
      public boolean verify(String requestedHost, SSLSession remoteServerSession) {
        return true;  // Noncompliant
      }
    });

    return urlConnection.getInputStream();
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="21" data-diff-type="compliant">
import java.io.InputStream;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

public InputStream doRequest() {
    URL url                          = new URL("https://example.org/");
    HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();

    return urlConnection.getInputStream();
}
</pre>
<h3>How does this work?</h3>
<p>To fix the vulnerability of disabled hostname validation, it is strongly recommended to first re-enable the default validation and fix the root
cause: the validity of the certificate.</p>
<h4>Use valid certificates</h4>
<p>If a hostname validation failure prevents connecting to the target server, keep in mind that <strong>one system’s code should not work around
another system’s problems</strong>, as this creates unnecessary dependencies and can lead to reliability issues.</p>
<p>Therefore, the first solution is to change the remote host’s certificate to match its identity. If the remote host is not under your control,
consider replicating its service to a server whose certificate you can change yourself.</p>
<p>In case the contacted host is located on a development machine, and if there is no other choice, try following this solution:</p>
<ul>
  <li> Create a self-signed certificate for that machine. </li>
  <li> Add this self-signed certificate to the system’s trust store. </li>
  <li> If the hostname is not <code>localhost</code>, add the hostname in the <code>/etc/hosts</code> file. </li>
</ul>
<p>Here is a sample command to import a certificate to the Java trust store:</p>
<pre>
keytool -import -alias myserver -file myserver.crt -keystore cacerts
</pre>
<h2>How to fix it in Java EE</h2>
<h3>Code examples</h3>
<p>The following code contains examples of disabled hostname validation.</p>
<p>The hostname validation gets disabled because <code>mail.smtp.ssl.checkserveridentity</code> is omitted. To enable validation, set it to
<code>true</code>.</p>
<h4>Noncompliant code example</h4>
<pre data-diff-id="11" data-diff-type="noncompliant">
import java.util.Properties;

public Properties prepareEmailConnection() {
    Properties props = new Properties();

    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); // Noncompliant
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");

    return props;
}
</pre>
<h4>Compliant solution</h4>
<pre data-diff-id="11" data-diff-type="compliant">
import java.util.Properties;

public Properties prepareEmailConnection() {
    Properties props = new Properties();

    props.put("mail.smtp.host", "smtp.gmail.com");
    props.put("mail.smtp.socketFactory.port", "465");
    props.put("mail.smtp.ssl.checkserveridentity", true);
    props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
    props.put("mail.smtp.auth", "true");
    props.put("mail.smtp.port", "465");

    return props;
}
</pre>
<h3>How does this work?</h3>
<p>To fix the vulnerability of disabled hostname validation, it is strongly recommended to first re-enable the default validation and fix the root
cause: the validity of the certificate.</p>
<h4>Use valid certificates</h4>
<p>If a hostname validation failure prevents connecting to the target server, keep in mind that <strong>one system’s code should not work around
another system’s problems</strong>, as this creates unnecessary dependencies and can lead to reliability issues.</p>
<p>Therefore, the first solution is to change the remote host’s certificate to match its identity. If the remote host is not under your control,
consider replicating its service to a server whose certificate you can change yourself.</p>
<p>In case the contacted host is located on a development machine, and if there is no other choice, try following this solution:</p>
<ul>
  <li> Create a self-signed certificate for that machine. </li>
  <li> Add this self-signed certificate to the system’s trust store. </li>
  <li> If the hostname is not <code>localhost</code>, add the hostname in the <code>/etc/hosts</code> file. </li>
</ul>
<p>Here is a sample command to import a certificate to the Java trust store:</p>
<pre>
keytool -import -alias myserver -file myserver.crt -keystore cacerts
</pre>
<h2>Resources</h2>
<h3>Standards</h3>
<ul>
  <li> OWASP - <a href="https://owasp.org/Top10/A02_2021-Cryptographic_Failures/">Top 10 2021 Category A2 - Cryptographic Failures</a> </li>
  <li> OWASP - <a href="https://owasp.org/Top10/A05_2021-Security_Misconfiguration/">Top 10 2021 Category A5 - Security Misconfiguration</a> </li>
  <li> OWASP - <a href="https://owasp.org/Top10/A07_2021-Identification_and_Authentication_Failures/">Top 10 2021 Category A7 - Identification and
  Authentication Failures</a> </li>
  <li> OWASP - <a href="https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure">Top 10 2017 Category A3 - Sensitive Data
  Exposure</a> </li>
  <li> OWASP - <a href="https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration">Top 10 2017 Category A6 - Security
  Misconfiguration</a> </li>
  <li> OWASP - <a href="https://mobile-security.gitbook.io/masvs/security-requirements/0x10-v5-network_communication_requirements">Mobile AppSec
  Verification Standard - Network Communication Requirements</a> </li>
  <li> OWASP - <a href="https://owasp.org/www-project-mobile-top-10/2016-risks/m3-insecure-communication">Mobile Top 10 2016 Category M3 - Insecure
  Communication</a> </li>
  <li> CWE - <a href="https://cwe.mitre.org/data/definitions/297">CWE-297 - Improper Validation of Certificate with Host Mismatch</a> </li>
  <li> STIG Viewer - <a href="https://stigviewer.com/stig/application_security_and_development/2023-06-08/finding/V-222550">Application Security and
  Development: V-222550</a> - The application must validate certificates by constructing a certification path to an accepted trust anchor. </li>
  <li> <a
  href="https://wiki.sei.cmu.edu/confluence/display/java/MSC61-J.+Do+not+use+insecure+or+weak+cryptographic+algorithms">https://wiki.sei.cmu.edu/confluence/display/java/MSC61-J.+Do+not+use+insecure+or+weak+cryptographic+algorithms</a> </li>
</ul>

